#include "icache/deinterlaced_item_id.h"
#include "icache/cache.h"

namespace icache {

bool deinterlaced_item_id::equal(const item_id & i) const 
{
	const deinterlaced_item_id * rhs = dynamic_cast<const deinterlaced_item_id *>(&i);
	if (rhs == 0)
		return false;
	return 
		origin->equal(*rhs->origin) && 
		upper_field == rhs->upper_field &&
		method == rhs->method;
}

string deinterlaced_item_id::name() const {
	string n = origin->name() + "_deinterlaced(";
	n += upper_field ? 'u' : 'l';
	n += method == method_duplicate ? 'd' : 'i';
	n += ')';
	return n;
}

void deinterlaced_item_id::serialize(std::ostream & o) const
	{ assert(!"n/i"); }

bool deinterlaced_item_id::loadable() const
	{ return origin->loadable(); }

void deinterlaced_item_id::load(byte_image & im) const 
{
	origin->load(im);
	deinterlace_in_place(im);
}

bool deinterlaced_item_id::requestable() const
	{ return origin->requestable(); }

void deinterlaced_item_id::request() const {
	cached_image_sptr i;
	while (!(i = my_cache.try_get(origin)))
		origin->request();
	cached_image_sptr d = cached_image::create(create_copy());
	deinterlace(i->im, d->im);
	my_cache.put(d);
}

void deinterlaced_item_id::deinterlace(byte_image const & interlaced, byte_image & dst) const
{
	dst.resize(interlaced.dim());
	//copy only one field
	unsigned y = upper_field ? 0 : 1;
	for (; y < interlaced.height(); y += 2)
		std::copy(interlaced.scan(y), interlaced.scan(y) + interlaced.width(), dst.scan(y));
	deinterlace_in_place(dst);
}

void deinterlaced_item_id::deinterlace_in_place(byte_image & im) const
{
	if (!upper_field && im.height() > 1)
		std::copy(im.scan(1), im.scan(1) + im.width(), im.scan(0)); //single copy up
	unsigned y = upper_field ? 0 : 1;

	if (method == method_duplicate) {
		//multiple copies down
		for (; y+1 < im.height(); y += 2)
			std::copy(im.scan(y), im.scan(y) + im.width(), im.scan(y+1));
	}
	else {
		//interpolations
		typedef img::BGRA<unsigned int> uint_color;
		for (; y+2 < im.height(); y += 2) {
			for (unsigned x = 0; x < im.width(); ++x)
				im(x, y+1) = (uint_color(im(x,y)) + uint_color(im(x,y+2))) / 2;
		}
		if (y+1 < im.height())
			std::copy(im.scan(y), im.scan(y) + im.width(), im.scan(y+1)); //copy down
	}
}

} //namespace icache
